
//Copyright 1997-2009 Syrinx Development, Inc.
//This file is part of the Syrinx Web Application Framework (SWAF).
// == BEGIN LICENSE ==
//
// Licensed under the terms of any of the following licenses at your
// choice:
//
//  - GNU General Public License Version 3 or later (the "GPL")
//    http://www.gnu.org/licenses/gpl.html
//
//  - GNU Lesser General Public License Version 3 or later (the "LGPL")
//    http://www.gnu.org/licenses/lgpl.html
//
//  - Mozilla Public License Version 1.1 or later (the "MPL")
//    http://www.mozilla.org/MPL/MPL-1.1.html
//
// == END LICENSE ==
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;

using Swaf;
using Swaf.BizObj;
using Swaf.Gui;
using Swaf.Security;

namespace eCom.Gui
{
	public class ProductWizardCheckoutBizProc : BaseBusinessProcess
	{
		protected bool m_setupCurrentStep = false;

		public ProductWizardCheckoutBizProc(ActiveBizProc procState)
			: base(procState)
		{
		}

		protected override void setupRuleNames()
		{
			//m_getBizObjDetailsRule = "getCheckOutWizard";
			//m_getBizObjListRule = "getSalesOrderWizardProducts";
		}

		protected override Privileges CurrentEditPrivilege
		{
			get { return Privileges.Edit; }
		}


		public void startWizard()
		{
			IBizObj wizState = CheckOutWizardState;
            if (wizState != null)
            {
                if (!(bool)wizState.get("wizardStarted"))
                {
                    wizState.put("wizardIndex", 0);
                    wizState.put("wizardStarted", true);
                }

                object useFullWizardMode = m_procState.get("useFullWizardMode");
                if (useFullWizardMode is string)
                {
                    if (((string)useFullWizardMode).ToLower().CompareTo("true") == 0 ||
                        m_procState.BPC.HostView.ViewName.EndsWith((string)useFullWizardMode))
                    {
                        App.sessionData["InFullCheckoutWizard"] = true;
                    }
                    else
                    {
                        App.sessionData["InFullCheckoutWizard"] = null;
                    }
                }
                updateActionState();
            }
		}

		public override void updateActionState()
		{
			base.updateActionState();

			IBizObj wizState = CheckOutWizardState;
			bool atFirst = false;
			bool wizardStarted = wizState==null?false:(bool)wizState.get("wizardStarted");
			bool failBecauseNotReadyToCheckout = false;
			if(!wizardStarted)
			{
				object waitToInitateWizard = m_procState.get("waitToInitiateWizard");
				if (Cmn.IsEmpty(waitToInitateWizard))
					waitToInitateWizard = App.sessionData.get("StartCheckoutWizard");
				if (waitToInitateWizard is string && ((string)waitToInitateWizard).ToLower().CompareTo("false") == 0) //!= 0)
					startWizard();
			}
			if (wizardStarted)
			{
				int index = (int)wizState.get("wizardIndex");
				if (index <= 0)
					atFirst = true;
				if (index >= ((IBizObjList)wizState.get("preCheckoutSteps")).numElements && !canUserMoveToCheckout())
					failBecauseNotReadyToCheckout = true;
			}

			((GenericAction)Actions["StartAndMove"]).Availability = wizardStarted ? ActionAvailability.none : ActionAvailability.enabled;
			
			if (!wizardStarted || (atFirst && failBecauseNotReadyToCheckout))
				((GenericAction)Actions["MoveNext"]).Availability = ActionAvailability.none;
			else
				((GenericAction)Actions["MoveNext"]).Availability =
					(wizardStarted && !failBecauseNotReadyToCheckout) ? ActionAvailability.enabled : ActionAvailability.disabled;

			if(atFirst && failBecauseNotReadyToCheckout)
				((GenericAction)Actions["MovePrev"]).Availability =  ActionAvailability.none;
			else
				((GenericAction)Actions["MovePrev"]).Availability = 
					(wizardStarted && !atFirst) ? ActionAvailability.enabled : ActionAvailability.disabled;
		}

		protected override void setupActions()
		{
			base.setupActions();
			Actions.addAction(new GenericAction("StartWizard", true, startWizard, this));
			Actions.addAction(new GenericAction("StartAndMove", true, startWizardAndMoveFirst, this));
		}


		
		protected IBizObj CheckOutWizardState
		{
			get
			{
				IBizObj info = App.sessionData["CheckoutWizardInfo"] as IBizObj;
				if (info == null)
				{
					object salesOrderId = m_procState.get("pid");
					if (salesOrderId != null)
					{
						IResults rc = App.ruleMgr.execute("getCheckOutWizard");
						App.sessionData["CheckoutWizardInfo"] = info = rc.CallResults as IBizObj;
					}
				}

				if (info != null)
				{
					if (State.State.get("finalCheckoutView") is string)
						info.put("finalCheckoutView", App.resMgr.resolve((string)State.State.get("finalCheckoutView")));
					if (State.State.get("initialCheckoutView") is string)
                        info.put("initialCheckoutView", App.resMgr.resolve((string)State.State.get("initialCheckoutView")));
				}

				return info;
			}
			set
			{
				App.sessionData["CheckoutWizardInfo"] = value;
			}
		}

		protected BitFlags WizardStepState
		{
			get
			{
				BitFlags b = App.sessionData["CheckoutWizardStepState"] as BitFlags;
				if (b == null)
					App.sessionData["CheckoutWizardStepState"] = b = new BitFlags();
				return b;
			}
		}

		protected override object[] getDetailsBizRuleParameters(object keyValue)
		{
			return new object[0];
		}

		protected override void getBizObjList()
		{
			IBizObj wizState = CheckOutWizardState;
			if (wizState != null)
			{
				m_bizobjs = App.bizObjMgr.createList("eComCheckoutWizardStep");
				int index = 0;

				foreach (IBizObj step in (IBizObjList)wizState.get("preCheckoutSteps"))
				{
					m_bizobjs.Add(step);
					step.put("stepCompleted", WizardStepState.getBit(index++));
					step.put("positionInParent", index);
					step.clearDirtyFlags();
				}

				IResults rc = App.ruleMgr.execute("getSalesOrderWizardProducts", m_procState.get("pid"));
				IBizObjList postSteps = rc.CallResults as IBizObjList;
				if (postSteps != null)
				{
					for (int p = 0; p < postSteps.numElements; ++p)
					{
						if (p == 0)
							postSteps[p].put("viewName", wizState.get("initialCheckoutView"));
						m_bizobjs.Add(postSteps[p]);

						postSteps[p].put("stepCompleted", WizardStepState.getBit(index++));
						postSteps[p].put("positionInParent", index);
						postSteps[p].clearDirtyFlags();
					}
				}
			}
		}

		protected void setupCurrentStep()
		{
			if (!m_setupCurrentStep)
			{
				string curView = "/" + m_procState.BPC.HostView.ViewName;
				IBizObj wizState = CheckOutWizardState;
				int curIndex = -1;
				if (SourceBizObjs != null)
				{
					int lastCurIndex = (int)wizState.get("wizardIndex");
					IBizObjList preSteps = (IBizObjList)wizState.get("preCheckoutSteps");

						foreach (IBizObj wizStep in m_bizobjs)
						if (!Cmn.IsEmpty(wizStep.get("viewName")) && curView.EndsWith(wizStep.get("viewName").ToString().ToLower().Replace('\\','/')))
						{
							if (curIndex < preSteps.numElements)
							{
								m_setupCurrentStep = true;
								if (lastCurIndex >= curIndex)
									wizState.put("wizardIndex", ++curIndex);
							}
							break;
						}
						else
							curIndex++;
					if (!m_setupCurrentStep)
						curIndex = lastCurIndex;
					if (curIndex >= 0 && curIndex < m_bizobjs.numElements)
					{
						m_currentBizObj = m_bizobjs[curIndex];
						if (curIndex >= preSteps.numElements)
							m_currentBizObj.put("inCheckout", true);
					}
				}
			}
		}

		public override void showData(ForceLevel level)
		{
			setupCurrentStep();
			base.showData(level);
		}

		protected override void getCurrentBizObj()
		{
			IBizObj wizState = CheckOutWizardState;
			setupCurrentStep();
			if (m_currentBizObj == null && wizState != null)
			{
				int index = (int)wizState.get("wizardIndex");
				if(index >=0 && index < SourceBizObjs.numElements)
					m_currentBizObj = SourceBizObjs[index];
			}
		}

		public override void clearRetrievedData()
		{
			//base.clearRetrievedData();
			//We never clear retrieved data for this class because we have been maintaining stepCompleted in the bizobjlist,
			//which is not persisted anywhere.
		}

		public virtual void startWizardAndMoveFirst()
		{
			IBizObj info = App.sessionData["CheckoutWizardInfo"] as IBizObj;
			if (info == null || Cmn.IsFalse(info.get("wizardStarted")))
				startWizard();
			move(true);
		}

		public override void moveNext()
		{
			move(true);
		}
		public override void movePrev()
		{
			move(false);
		}


		protected int searchForFirstStepNeedingToBeDone(int nextIndex)
		{
			bool pastPreCheckoutSteps = nextIndex >= ((IBizObjList)CheckOutWizardState.get("preCheckoutSteps")).numElements;
			for (int p = 0; p < nextIndex; ++p)
			{
				IBizObj wizStep = SourceBizObjs[p];
				WizStepOptions completeOption = (WizStepOptions)wizStep.get("completeOption");
				if (!(bool)wizStep.get("stepCompleted") &&
					(completeOption == WizStepOptions.mustCompleteBeforeMoveForward ||
					(pastPreCheckoutSteps && completeOption == WizStepOptions.requiredBeforeCheckout)))
					return p;
			}
			return nextIndex;
		}

		protected bool canUserMoveToCheckout()
		{ 
			IBizObj order = m_procState.get("orderInfo", false) as IBizObj;
			IBizObj wizState = CheckOutWizardState;
			IBizObjList preSteps = (IBizObjList)wizState.get("preCheckoutSteps");
			for (int p = 0; p < preSteps.numElements; p++)
			{
				IBizObj wizStep = SourceBizObjs[p];
				if (!(bool)wizStep.get("stepCompleted") && (WizStepOptions)wizStep.get("completeOption") != WizStepOptions.optional)
					return false;
			}
			if ((order == null || ((IBizObjList)order.get("items")).numElements == 0))
				return false;
			return true;
		}

		protected void move(bool forward)
		{
			setupCurrentStep();
			IBizObj wizState = CheckOutWizardState;
			int index = (int)wizState.get("wizardIndex");
			string curView = "/" + m_procState.BPC.HostView.ViewName;

			string nextView = null;
			IBizObj wizStep = null;
			bool wizCompleted = false;
			IBizObjList preSteps = (IBizObjList)wizState.get("preCheckoutSteps");

			if (index >=0 && index < SourceBizObjs.numElements)
				wizStep = SourceBizObjs[index];

			if (wizStep != null)
			{
				//This wizard does the processing of pre-checkout steps for now
				if (index < preSteps.numElements && !(bool)wizStep.get("stepCompleted"))
				{
					IResults rc = App.ruleMgr.execute("isProductOrChildInSalesOrder", wizStep.get("product.id"));
					if (rc.CallResults is bool && (bool)rc.CallResults)
						wizStep.put("stepCompleted", true);
				}

				if (((bool)wizStep.get("stepCompleted") ||
					(((WizStepOptions)wizStep.get("completeOption")) != WizStepOptions.mustCompleteBeforeMoveForward
						&& curView.EndsWith(wizStep.get("viewName").ToString().ToLower())) ||
					!forward))
				{
					if ((bool)wizStep.get("stepCompleted"))
						WizardStepState.setBit(index, true);
					index += forward ? 1 : -1;
					if (index < SourceBizObjs.numElements)
						wizStep = SourceBizObjs[index = searchForFirstStepNeedingToBeDone(index)];
					else
					{
						wizStep = null;
						wizCompleted = true;
					}
				}
			}
			else if(index == -1)
			{
				index += forward ? 1 : -1;
				if (index < SourceBizObjs.numElements)
					wizStep = SourceBizObjs[index = searchForFirstStepNeedingToBeDone(index)];
			}

			if (wizStep != null || (wizStep == null && wizCompleted))
			{
				if (index == preSteps.numElements)
					nextView = (string)wizState.get("initialCheckoutView");
				else if (!wizCompleted)
				{
					nextView = (string)wizStep.get("viewName");
					Debug.Assert(nextView != null);
				}
				else
				{
					nextView = (string)wizState.get("finalCheckoutView");
					processCheckOut();
				}
				wizState.put("currentStep", wizStep);
				wizState.put("wizardIndex", index);
				m_setupCurrentStep = true;

				string initView = (string)wizState.get("initialCheckoutView");

				if (!Cmn.IsEmpty(nextView) && string.Compare(nextView,curView,true) != 0)
					m_procState.BPC.HostView.gotoView(nextView);
			}
		}
		protected bool processCheckOut()
		{
			IBizObj order = m_procState.get("orderInfo") as IBizObj;
			if (order != null)
			{
				Uri first = (Uri)App.sessionData.get("firstUrl");
				IResults rc = App.ruleMgr.execute("checkOutOrder", order, first);

				if (rc.ExceptionInfo != null)
				{
					m_procState.BPC.Messenger.add("Error-SalesOrderCheckOutError.", null);
					return false;
				}
				else
				{
					App.sessionData["LastEComOrderId"] = App.sessionData["CurrentOrderId"];
					App.sessionData["CurrentOrderId"] = null;
					App.sessionData["CheckoutWizardStepState"] = null;
					//The following is a hack.. Somehow, other features need to be a part of the wizard process.
					//This is the next level of work - Jun16,08
					App.sessionData["startedRes"] = null;
					//App.sessionData["InFullCheckoutWizard"] = null;
					CheckOutWizardState = null;
				}
				return true;
			}
			return false;
		}
		protected override object[] getUpdateBizRuleParameters(IBizObj bizObj)
		{
			return new object[] { bizObj };
		}
	}
}
